home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Workbench Design
/
WB Collection.iso
/
workbench werkzeuge
/
assign manager
/
assignwedge
/
source
/
assignwedge.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-04-07
|
24KB
|
1,067 lines
/*
** AssignWedge - AmigaDOS 2.04 utility
**
** Copyright © 1992-1994 by Olaf `Olsen' Barthel
** All Rights Reserved
**
** :ts=4
*/
#include <intuition/intuitionbase.h>
#include <workbench/startup.h>
#include <dos/dosextens.h>
#include <dos/dostags.h>
#include <exec/execbase.h>
#include <exec/memory.h>
#include <libraries/locale.h>
#include <libraries/asl.h>
#include <clib/intuition_protos.h>
#include <clib/utility_protos.h>
#include <clib/locale_protos.h>
#include <clib/alib_protos.h>
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/asl_protos.h>
#include <pragmas/intuition_pragmas.h>
#include <pragmas/utility_pragmas.h>
#include <pragmas/locale_pragmas.h>
#include <pragmas/exec_pragmas.h>
#include <pragmas/dos_pragmas.h>
#include <pragmas/asl_pragmas.h>
#include <string.h>
#include <stdarg.h>
/* Create the requester strings. */
#define CATCOMP_ARRAY
#include "AssignWedge.h"
/* The requester selection IDs. */
enum { REQ_CANCEL, REQ_RETRY, REQ_ASSIGN, REQ_MOUNT, REQ_DENY };
/* Some handy signal macros. */
#define SIG_KILL SIGBREAKF_CTRL_C
#define SIG_NOTIFY (1L << MainPort -> mp_SigBit)
/* The MC680x0 `jump to absolute address' opcode. */
#define JMP_ABS 0x4EF9
/* A simple wedge definition which is to consist of a jmp
* instruction and the destination of the jump.
*/
struct Wedge
{
UWORD Command;
ULONG Location;
};
/* Process and command names which are no longer allowed to
* access certain paths will be identified by information
* to be found in a list. The following structure definition
* holds the necessary data (name and process base address).
*/
struct DenyNode
{
struct MinNode Node;
struct Process *Process;
LONG DenyEmpty;
STRPTR Name,
ProgramName;
};
/* The library vector offset of the intuition.library routine to patch. */
extern ULONG __far LVOEasyRequestArgs;
/* The version ID tag. */
STATIC UBYTE Version[] = "\0$VER: AssignWedge 1.5 (18.1.95)\r\n";
/* Global and shared library identifiers. */
struct IntuitionBase *IntuitionBase;
struct ExecBase *SysBase;
struct DosLibrary *DOSBase;
struct Library *UtilityBase,
*AslBase;
/* Locale support. */
struct LocaleBase *LocaleBase;
struct Catalog *Catalog;
/* Registration of programs which are not allowed to
* access certain devices.
*/
struct SignalSemaphore DenySemaphore;
struct MinList DenyList;
/* The following counter and the associated access semaphore help
* to keep track of the number of programs currently using the
* patched EasyRequestArgs() routine.
*/
struct SignalSemaphore RunSemaphore;
LONG RunCount;
/* Handshake data. */
struct Process *MainProcess;
struct MsgPort *MainPort;
BOOL Removed;
/* To compensate for possible incompatibilities introduced by internationalized
* requester texts, we will try to determine the text to turn up when an
* `please insert volume' requester is opened. The `SearchName' will receive
* the string to look for.
*/
UBYTE SearchName[256];
/* Function prototypes. */
LONG __saveds Main(VOID);
STRPTR __regargs GetString(LONG ID);
LONG __saveds __asm NewEasyRequestArgs(register __a0 struct Window *Window,register __a1 struct EasyStruct *EasyStruct,register __a2 ULONG *IDCMPPtr,register __a3 APTR *Args);
LONG (* __asm OldEasyRequestArgs)(register __a0 struct Window *,register __a1 struct EasyStruct *,register __a2 ULONG *,register __a3 APTR *,register __a6 struct IntuitionBase *);
LONG __stdargs StackCall(LONG *Success,LONG StackSize,LONG ArgCount,LONG (* __stdargs Function)(),...);
VOID __stdargs SPrintf(STRPTR buffer,STRPTR formatString,...);
VOID CheckIn(VOID);
VOID CheckOut(VOID);
LONG __saveds
Main()
{
struct WBStartup *WBenchMsg;
LONG ReturnCode = RETURN_FAIL;
/* Set up ExecBase */
SysBase = *(struct ExecBase **)4;
/* Determine current process identifier. */
MainProcess = (struct Process *)SysBase -> ThisTask;
/* Are we running from CLI? If not, wait for Workbench
* startup message.
*/
if(!MainProcess -> pr_CLI)
{
WaitPort(&MainProcess -> pr_MsgPort);
WBenchMsg = (struct WBStartup *)GetMsg(&MainProcess -> pr_MsgPort);
}
else
WBenchMsg = NULL;
/* Try to find the global handshake port and if present
* send a termination signal.
*/
Forbid();
if(MainPort = FindPort("AssignWedge Rendezvous"))
{
Signal(MainPort -> mp_SigTask,SIG_KILL);
ReturnCode = RETURN_OK;
Permit();
}
else
{
Permit();
/* Are we running under Kickstart version 37 or higher? */
if(SysBase -> LibNode . lib_Version > 36)
{
/* Create the global handshake port. */
if(MainPort = CreateMsgPort())
{
/* Give it a name and add it to the public list. */
MainPort -> mp_Node . ln_Name = "AssignWedge Rendezvous";
AddPort(MainPort);
/* Open the required libraries. */
if(DOSBase = (struct DosLibrary *)OpenLibrary("dos.library",37))
{
if(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",37))
{
if(UtilityBase = OpenLibrary("utility.library",37))
{
if(AslBase = OpenLibrary(AslName,37))
{
struct Wedge *Wedge;
/* Try to open locale.library, but don't panic
* if it's not available.
*/
if(LocaleBase = (struct LocaleBase *)OpenLibrary("locale.library",38))
{
if(!(Catalog = OpenCatalog(NULL,"assignwedge.catalog",
OC_BuiltInLanguage, "english",
OC_BuiltInCodeSet, 0,
TAG_DONE)))
{
CloseLibrary((struct Library *)LocaleBase);
LocaleBase = NULL;
}
}
/* Initialize the access semaphore. */
InitSemaphore(&RunSemaphore);
RunCount = 0;
/* Initialize the access semaphore and
* the list of programs to which access
* to certain devices has been denied.
*/
InitSemaphore(&DenySemaphore);
NewList((struct List *)&DenyList);
/* Allocate a system library function wedge. */
if(Wedge = AllocMem(sizeof(struct Wedge),MEMF_PUBLIC))
{
struct DenyNode *NextNode,
*DenyNode;
UBYTE LocalBuffer[80];
/* Initialize the wedge. */
Wedge -> Command = JMP_ABS;
Wedge -> Location = (ULONG)NewEasyRequestArgs;
Removed = FALSE;
/* Install the wedge. */
Forbid();
OldEasyRequestArgs = (LONG (* __asm)())SetFunction((struct Library *)IntuitionBase,(LONG)&LVOEasyRequestArgs,(ULONG (*)())Wedge);
/* Make sure the data gets written to memory. */
CacheClearU();
/* Put up an example requester. Note: this requester
* will be trapped by the wedge routine, giving us
* the string to look for in the future.
*/
SPrintf(LocalBuffer,"AssignWedge.%08lx:",MainProcess);
ErrorReport(ERROR_DEVICE_NOT_MOUNTED,REPORT_INSERT,(ULONG)LocalBuffer,NULL);
/* We're up and running now. Note that the
* Forbid() will be broken by the Wait() for
* a ^C signal.
*/
Wait(SIG_KILL);
/* We are no longer running,
* tell the wedge routine to
* skip the `access denied'
* part which requires the
* list to be initialized.
*/
Removed = TRUE;
/* Redirect the wedge pointer to
* the original routine.
*/
Wedge -> Location = (ULONG)OldEasyRequestArgs;
/* Make sure that the data
* gets written to memory.
*/
CacheClearU();
/* Clear pending signals. */
SetSignal(0,SIG_NOTIFY);
/* Turn the multitasking back on. */
Permit();
/* Wait until our wedge routine
* is no longer in use.
*/
while(RunCount)
Wait(SIG_NOTIFY);
/* Clear the `access denied' list. */
DenyNode = (struct DenyNode *)DenyList . mlh_Head;
while(NextNode = (struct DenyNode *)DenyNode -> Node . mln_Succ)
{
FreeVec(DenyNode);
DenyNode = NextNode;
}
/* Successful termination. */
ReturnCode = RETURN_OK;
}
/* Close the resources
* we had allocated,
* but *not* the wedge
* memory.
*/
if(Catalog)
CloseCatalog(Catalog);
if(LocaleBase)
CloseLibrary((struct Library *)LocaleBase);
CloseLibrary(AslBase);
}
CloseLibrary(UtilityBase);
}
CloseLibrary((struct Library *)IntuitionBase);
}
CloseLibrary((struct Library *)DOSBase);
}
/* Remove the global handshake port. */
RemPort(MainPort);
DeleteMsgPort(MainPort);
}
}
}
/* If run from Workbench, reply the startup message. */
if(WBenchMsg)
{
Forbid();
ReplyMsg(&WBenchMsg -> sm_Message);
}
/* That's all folks. */
return(ReturnCode);
}
/* GetString(LONG ID):
*
* Fetch a text from the database.
*/
STRPTR __regargs
GetString(LONG ID)
{
STRPTR Builtin = "";
WORD i;
/* Try to find the builtin string to match the ID we received. */
if(CatCompArray[ID] . cca_ID != ID)
{
for(i = 0 ; i < (sizeof(CatCompArray) / sizeof(struct CatCompArrayType)) ; i++)
{
if(CatCompArray[i] . cca_ID == ID)
{
Builtin = CatCompArray[i] . cca_Str;
break;
}
}
}
else
Builtin = CatCompArray[ID] . cca_Str;
/* If locale.library is installed and the database catalog was
* successfully opened, query the library's idea of the corresponding
* text string. Otherwise, return the builtin string.
*/
if(LocaleBase)
return(GetCatalogStr(Catalog,ID,Builtin));
else
return(Builtin);
}
/* SPrintf(STRPTR buffer,STRPTR formatString,...):
*
* Your easy text formatting routine.
*/
VOID __stdargs
SPrintf(STRPTR buffer,STRPTR formatString,...)
{
va_list varArgs;
va_start(varArgs,formatString);
RawDoFmt(formatString,varArgs,(VOID (*)())(VOID (*))"\x16\xC0\x4E\x75",buffer);
va_end(varArgs);
}
/* CheckIn():
*
* Mark the patch as having another customer.
*/
VOID
CheckIn()
{
/* Increment the usage count. */
ObtainSemaphore(&RunSemaphore);
RunCount++;
ReleaseSemaphore(&RunSemaphore);
}
/* CheckOut():
*
* Decrement the patch usage counter and signal the
* main process to check the usage counter.
*/
VOID
CheckOut()
{
/* Decrement usage count. */
ObtainSemaphore(&RunSemaphore);
RunCount--;
ReleaseSemaphore(&RunSemaphore);
/* Tell the main process to take a
* look at the usage count.
*/
Signal((struct Task *)MainProcess,SIG_NOTIFY);
}
/* RealEasyRequestArgs():
*
* Custom version of EasyRequestArgs().
*/
LONG __stdargs
RealEasyRequestArgs(struct Window *Window,struct EasyStruct *EasyStruct,ULONG *IDCMPPtr,APTR *Args)
{
struct Process *ThisProcess = (struct Process *)SysBase -> ThisTask;
LONG Result;
/* Increment the usage count. */
CheckIn();
/* Is the caller a process, i.e. will it be able to use all
* DOS routines?
*/
if(ThisProcess -> pr_Task . tc_Node . ln_Type == NT_PROCESS)
{
/* Do the arguments match the pattern we had expected and
* are DOS requesters enabled?
*/
if(!Strnicmp(EasyStruct -> es_TextFormat,"%s",2) && Args && ThisProcess -> pr_WindowPtr != (APTR)-1)
{
/* Did we get any calling parameters? */
if(Args[0])
{
/* Does the first argument match the `please insert volume...' title? */
if(!Stricmp(Args[0],SearchName))
{
struct EasyStruct __aligned Easy = *EasyStruct;
UBYTE DirBuffer[512 + 60];
STRPTR HailBuffer;
struct DenyNode *DenyNode;
struct FileRequester *AslFileRequest;
struct Screen *FirstScreen;
ULONG IntuiLock;
BPTR In,Out;
/* Gain access to the list of
* programs to which access to
* some devices has been denied.
*/
ObtainSemaphore(&DenySemaphore);
/* If this process has a CLI structure
* attached, look for a command name
* to match a list entry.
*/
if(ThisProcess -> pr_CLI)
{
/* Process the list... */
for(DenyNode = (struct DenyNode *)DenyList . mlh_Head ; DenyNode -> Node . mln_Succ ; DenyNode = (struct DenyNode *)DenyNode -> Node . mln_Succ)
{
/* Does this entry refer to
* a command name?
*/
if(DenyNode -> ProgramName[0])
{
/* Does the name of the device
* in question match the name
* in the list entry?
*/
if(!Stricmp(DenyNode -> Name,Args[1]))
{
/* Obtain the name of the program
* currently running.
*/
if(GetProgramName(DirBuffer,512))
{
/* Does the name match the one
* in the list entry?
*/
if(!Stricmp(FilePart(DirBuffer),DenyNode -> ProgramName))
{
/* Release the access semaphore. */
ReleaseSemaphore(&DenySemaphore);
/* Decrement usage count. */
CheckOut();
/* Return failure. */
return(REQ_CANCEL);
}
}
}
}
else
{
/* This might be an `empty' Shell. Let's have a look. */
if(!GetProgramName(DirBuffer,512))
DirBuffer[0] = 0;
/* No command loaded? */
if(!DirBuffer[0])
{
/* Release the access semaphore. */
ReleaseSemaphore(&DenySemaphore);
/* Decrement usage count. */
CheckOut();
/* Return failure. */
return(REQ_CANCEL);
}
}
}
}
else
{
/* Run down the list. */
for(DenyNode = (struct DenyNode *)DenyList . mlh_Head ; DenyNode -> Node . mln_Succ ; DenyNode = (struct DenyNode *)DenyNode -> Node . mln_Succ)
{
/* Does the process identifier match the
* one in the list entry?
*/
if(DenyNode -> Process == ThisProcess)
{
/* Does the name of the device in
* question match the one in the
* list entry?
*/
if(!Stricmp(DenyNode -> Name,Args[1]))
{
/* Release the access semaphore. */
ReleaseSemaphore(&DenySemaphore);
/* Decrement usage count. */
CheckOut();
/* Return failure. */
return(REQ_CANCEL);
}
}
}
}
/* Release the access semaphore. */
ReleaseSemaphore(&DenySemaphore);
/* Split the buffer to create the directory
* requester title string.
*/
HailBuffer = DirBuffer + 512;
/* Fill in the `Retry|Assign|Mount|Deny|Cancel' buttons. */
Easy . es_GadgetFormat = GetString(MSG_PROMPT_GAD);
/* Put up the requester and decide what to do. */
switch(Result = OldEasyRequestArgs(Window,&Easy,IDCMPPtr,Args,IntuitionBase))
{
case REQ_ASSIGN:
/* Try to obtain the name of the current directory,
* most programs to look for assignments or volume
* names will be happy if assignments are made
* referring to their home directories.
*/
if(ThisProcess -> pr_HomeDir)
{
if(!NameFromLock(ThisProcess -> pr_HomeDir,DirBuffer,512))
DirBuffer[0] = 0;
}
else
DirBuffer[0] = 0;
/* No success? */
if(!DirBuffer[0])
{
if(!GetCurrentDirName(DirBuffer,512))
DirBuffer[0] = 0;
}
/* Set up the window title. */
SPrintf(HailBuffer,GetString(MSG_HAIL_GAD),Args[1]);
/* create the directory requester. */
if(AslFileRequest = (struct FileRequester *)AllocAslRequestTags(ASL_FileRequest,
ASLFR_InitialDrawer, DirBuffer,
ASLFR_TitleText, HailBuffer,
ASLFR_PositiveText, GetString(MSG_ASSIGN_GAD),
ASLFR_DrawersOnly, TRUE,
ASLFR_PrivateIDCMP, TRUE,
/* These are actually for asl.library v36/v37. */
ASL_FuncFlags, FILF_NEWIDCMP,
ASL_ExtFlags1, FIL1F_NOFILES,
Window ? ASLFR_Window : TAG_IGNORE, Window,
TAG_DONE))
{
/* Remember the first screen ID. */
IntuiLock = LockIBase(NULL);
FirstScreen = IntuitionBase -> FirstScreen;
UnlockIBase(IntuiLock);
/* Did we receive a window pointer to work with? */
if(Window)
{
/* Move the screen the requester is to appear on
* up if necessary.
*/
if(Window -> WScreen -> TopEdge > 0)
MoveScreen(Window -> WScreen,0,-Window -> WScreen -> TopEdge);
/* Move the screen to the front. */
ScreenToFront(Window -> WScreen);
}
else
{
/* Get the current default public screen. */
struct Screen *Workbench = LockPubScreen(NULL);
/* Did we succeed in locking it? */
if(Workbench)
{
/* Move the screen the requester is to appear on
* up if necessary.
*/
if(Workbench -> TopEdge > 0)
MoveScreen(Workbench,0,-Workbench -> TopEdge);
/* Move the screen to the front. */
ScreenToFront(Workbench);
/* Release the screen again. */
UnlockPubScreen(NULL,Workbench);
}
}
/* Display the requester. */
while(AslRequest(AslFileRequest,NULL))
{
APTR OldWindowPtr = ThisProcess -> pr_WindowPtr;
BPTR FileLock;
/* Disable the system requesters. */
ThisProcess -> pr_WindowPtr = (APTR)-1;
/* Try to access the directory the
* user has just selected.
*/
if(FileLock = Lock(AslFileRequest -> fr_Drawer,ACCESS_READ))
{
/* Try to create the assignment. */
if(!AssignLock(Args[1],FileLock))
{
/* Oops, something went wrong. */
if(Window)
DisplayBeep(Window -> WScreen);
else
DisplayBeep(NULL);
UnLock(FileLock);
}
else
{
/* Restore the window pointer. */
ThisProcess -> pr_WindowPtr = OldWindowPtr;
break;
}
}
else
{
if(Window)
DisplayBeep(Window -> WScreen);
else
DisplayBeep(NULL);
}
/* Restore the window pointer. */
ThisProcess -> pr_WindowPtr = OldWindowPtr;
}
/* Free the requester data. */
FreeAslRequest(AslFileRequest);
/* Pop the screen which was frontmost
* before the requester was displayed
* back to the front.
*/
IntuiLock = LockIBase(0);
if(FirstScreen == IntuitionBase -> FirstScreen)
UnlockIBase(IntuiLock);
else
{
struct Screen *Screen = IntuitionBase -> FirstScreen;
BOOL IsValid = FALSE;
/* Try to determine if the screen ID we
* remembered is still valid.
*/
while(Screen && !IsValid)
{
if(Screen == FirstScreen)
IsValid = TRUE;
else
Screen = Screen -> NextScreen;
}
Forbid();
UnlockIBase(IntuiLock);
/* Push the screen to the front. */
if(IsValid)
ScreenToFront(FirstScreen);
Permit();
}
}
/* Tell AmigaDOS to take a second look at the
* device list.
*/
Result = REQ_RETRY;
break;
case REQ_MOUNT:
/* Open input stream. */
if(In = Open("NIL:",MODE_OLDFILE))
{
/* Open output stream. */
if(Out = Open("NIL:",MODE_OLDFILE))
{
APTR OldPtr = ThisProcess -> pr_WindowPtr;
/* Enter the mount command string. */
SPrintf(DirBuffer,"Mount >NIL: <NIL: %s:",Args[1]);
/* Disable DOS requesters. */
ThisProcess -> pr_WindowPtr = (APTR)-1;
/* Execute the mount command. */
SystemTags(DirBuffer,
NP_Cli, TRUE,
NP_CloseInput, TRUE,
NP_CloseOutput, TRUE,
SYS_UserShell, TRUE,
SYS_Input, In,
SYS_Output, Out,
TAG_DONE);
/* Restore window pointer. */
if(ThisProcess -> pr_WindowPtr == (APTR)-1)
ThisProcess -> pr_WindowPtr = OldPtr;
}
else
Close(In);
}
/* Tell AmigaDOS to take a second look at the
* device list.
*/
Result = REQ_RETRY;
break;
case REQ_DENY:
/* If not about to be removed, allocate an `access denied' node. */
if(!Removed)
{
WORD ProgramNameLen = 0,
DeviceNameLen;
LONG DenyEmpty = FALSE;
/* Remember the length of the device name. */
DeviceNameLen = strlen(Args[1]) + 1;
/* If this process has a CLI structure attached,
* remember the name of the program.
*/
if(ThisProcess -> pr_CLI)
{
/* Is there a command making the request? */
if(!GetProgramName(DirBuffer,512))
DirBuffer[0] = 0;
/* Keep the name. */
if(DirBuffer[0])
ProgramNameLen = strlen(FilePart(DirBuffer)) + 1;
else
DenyEmpty = TRUE;
}
/* Allocate a new deny node. */
if(DenyNode = (struct DenyNode *)AllocVec(sizeof(struct DenyNode) + DeviceNameLen + ProgramNameLen,MEMF_CLEAR))
{
/* Deny `empty' Shells? */
DenyNode -> DenyEmpty = DenyEmpty;
/* Fill in the current process ID. */
DenyNode -> Process = ThisProcess;
/* Copy the name of the device in question. */
strcpy(DenyNode -> Name = (STRPTR)(DenyNode + 1),Args[1]);
/* Copy the program name if possible. */
if(ProgramNameLen)
strcpy(DenyNode -> ProgramName = DenyNode -> Name + DeviceNameLen,FilePart(DirBuffer));
else
DenyNode -> ProgramName = "";
/* Gain access to the list. */
ObtainSemaphore(&DenySemaphore);
/* Add the entry to the list. */
AddTail((struct List *)&DenyList,(struct Node *)DenyNode);
/* Release the semaphore again. */
ReleaseSemaphore(&DenySemaphore);
}
}
/* Return failure. */
Result = REQ_CANCEL;
break;
}
/* Decrement usage count. */
CheckOut();
/* Return the result. */
return(Result);
}
}
}
}
/* In any other case, use the standard call. */
Result = OldEasyRequestArgs(Window,EasyStruct,IDCMPPtr,Args,IntuitionBase);
/* Decrement usage count. */
CheckOut();
/* Return the result. */
return(Result);
}
/* NewEasyRequestArgs():
*
* A custom version of the original EasyRequest() routine which
* is to provide enhanced options whenever a DOS handler puts
* up a `REPORT_INSERT' style requester.
*/
LONG __saveds __asm
NewEasyRequestArgs(register __a0 struct Window *Window,register __a1 struct EasyStruct *EasyStruct,register __a2 ULONG *IDCMPPtr,register __a3 APTR *Args)
{
struct Process *ThisProcess = (struct Process *)SysBase -> ThisTask;
/* This may be the first call to the new routine, made by the
* main program trying to determine the text to look for in
* future requesters.
*/
if(!SearchName[0] && ThisProcess == MainProcess)
{
strcpy(SearchName,Args[0]);
return(REQ_CANCEL);
}
else
{
LONG Success,Result;
/* Allocate extra stack space, call the special routine. */
Result = StackCall(&Success,8192,4,RealEasyRequestArgs,Window,EasyStruct,IDCMPPtr,Args);
/* If the call did not succeed, do it the standard way. */
if(!Success)
{
/* Increment the usage count. */
CheckIn();
/* Call the original routine. */
Result = OldEasyRequestArgs(Window,EasyStruct,IDCMPPtr,Args,IntuitionBase);
/* Decrement usage count. */
CheckOut();
}
/* Return the result. */
return(Result);
}
}